﻿using System;
using System.Collections.Generic;

namespace ProLinq.Projection.Configuration
{
	/// <summary>
	/// Describes projection of one type to another.
	/// </summary>
	public class Projection : ICloneable
	{
		private Delegate _factory;

		public Projection(Type sourceType, Type resultType)
		{
			this.SourceType = sourceType;
			this.DestinationType = resultType;
			this.Map = new PropertyMapCollection(sourceType, resultType);
		}

		/// <summary>
		/// Gets the projection source type.
		/// </summary>
		public Type SourceType { get; private set; }

		/// <summary>
		/// Gets the projection result type.
		/// </summary>
		public Type DestinationType { get; private set; }

		/// <summary>
		/// Gets the map of projection's types properties.
		/// </summary>
		public IList<PropertyMap> Map { get; internal set; }

		/// <summary>
		/// Gets or sets a factory for creating the result type out of source type. 
		/// </summary>
		public Delegate Factory
		{
			get { return this._factory; }
			set
			{
				//var method = value.Method;
				//var args = method.GetParameters();
				//if (!DestinationType.IsAssignableFrom(method.ReturnType)
				//	|| args.Length != 1
				//	|| !args[0].ParameterType.IsAssignableFrom(SourceType))
				//{
				//	throw new ArgumentException("Invalid factory method.");
				//}

				this._factory = value;
			}
		}

		#region ICloneable Members

		public object Clone()
		{
			var projection = (Projection)this.MemberwiseClone();
			projection.Map = new List<PropertyMap>(this.Map);
			return projection;
		}

		#endregion
	}
}